package com.showsu.editor.controller.biz;

import cn.hutool.core.util.PhoneUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.showsu.editor.controller.BaseController;
import com.showsu.editor.entity.doo.*;
import com.showsu.editor.entity.dto.IdentifycodeRequestDTO;
import com.showsu.editor.entity.dto.LoginRequestDTO;
import com.showsu.editor.entity.dto.WechatLoginRequestDTO;
import com.showsu.editor.entity.po.TblUser;
import com.showsu.editor.entity.po.TblUserExppackage;
import com.showsu.editor.entity.vo.request.RequestVO;
import com.showsu.editor.entity.vo.response.UserVO;
import com.showsu.editor.enums.*;
import com.showsu.editor.service.*;
import com.showsu.editor.session.ISession;
import com.showsu.editor.utils.*;
import com.showsu.editor.utils.aliyun.AliyunCaptchaUtil;
import com.showsu.editor.utils.sms.AliyunSMSUtil;
import com.showsu.editor.utils.sms.IdentifyCode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * @Author: William
 * @Description:
 * @Date: Created in 5:16 下午 2024/9/12
 * @Modified By:
 */
@RestController
@RequestMapping("/api/user")
@Slf4j
@Api(value = "UserController", tags = "用户相关")
public class UserController extends BaseController {

    @Value("${wechat.pc.appid}")
    private String appId;

    @Value("${wechat.pc.secret}")
    private String secret;

    private static final int length = 3;

    @Autowired
    private AliyunCaptchaUtil aliyunCaptchaUtil;

    @Autowired
    private AliyunSMSUtil aliyunSMSUtil;

    @Autowired
    private ISmsLogService smsLogService;

    @Autowired
    private IUserLoginLogService userLoginLogService;

    @Autowired
    private IVipGoodsService vipGoodsService;

    @Autowired
    private IUserPrivilegeService userPrivilegeService;

    @Autowired
    private IUserExppackageService userExppackageService;

    /**
     * 微信官方文档：https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/Wechat_Login.html
     * 此接口仅用于后端调试。实际功能使用微信前端js，将二维码内嵌到登录页面。
     *
     * @return
     */
    @PostMapping("/wechat/login/qrcode")
    @ApiOperation(value = "获取微信登录二维码", notes = "获取微信登录二维码")
    @ResponseBody
    public BsResult wechatLoginQRCode() {
        StringBuilder url = new StringBuilder("https://open.weixin.qq.com/connect/qrconnect?appid=").append(appId)
                .append("&redirect_uri=https://creator.datashows.cn/api/user/wechat/login")
                .append("&response_type=code&scope=snsapi_login#wechat_redirect");
        return BsResult.success(url.toString());
    }

    @PostMapping("/identifycode")
    @ApiOperation(value = "获取短信验证码", notes = "获取短信验证码")
    @ResponseBody
    public BsResult identifycode(@RequestBody IdentifycodeRequestDTO dto) {
        //检查手机号码的有效性
        if (StringUtils.isBlank(dto.getMobile()) || !PhoneUtil.isMobile(dto.getMobile())) {
            return BsResult.error(ResultCode.PARAM_VALID_ERROR);
        }
        if (StringUtils.isBlank(dto.getCaptchaVerifyParam())) {
            return BsResult.error(ResultCode.PARAM_VALID_ERROR);
        }
        //检查安全验证码的正误
        Boolean checkOk = aliyunCaptchaUtil.start(dto.getCaptchaVerifyParam());
        if (!checkOk) {
            return BsResult.error(ResultCode.VERIFICATION_FAILED);
        }
        //发送短信验证码
        SmsLog lastSms = smsLogService.queryLastUnckeckedOneByMobile(dto.getMobile());
        //如有在有效期内的验证码（5分钟） ，则返回重复发送
        if (lastSms != null && DateUtil.getMinuteOfTwoDate(lastSms.getCreateTime(), new Date()) < 5) {
            return BsResult.error(ResultCode.CODE_REPEAT);
        }
        IdentifyCode ic = new IdentifyCode().setCode(CodeGenerator.generate6L()).setCodeId(SessionIdGenerator.generate()).setMobile(dto.getMobile());
        SMSTemplateEnum smsTemplateEnum = SMSTemplateEnum.SHOWSU_EDITOR_LOGIN;
        Boolean sendResult = aliyunSMSUtil.send(dto.getMobile(), ic.getCode().toString(), smsTemplateEnum.getAliyunTemplatCode(), smsTemplateEnum.getSignature());
        smsLogService.saveRecord(dto.getMobile(), ic.getCode().toString(), getClientRequest(getRequest()).getClientIp());
        Map<String, Object> result = new HashMap<>();
        result.put("result", sendResult);
        result.put("message", sendResult ? "发送成功" : "发送失败");
        return BsResult.success(result);
    }

    @PostMapping("/wechat/login")
    @ApiOperation(value = "用户登录", notes = "用户通过微信扫码登录，前端将二维码内嵌到页面，通过js获取到微信回调的code/state后再调起本接口")
    @ResponseBody
    public BsResult wechatLogin(@RequestBody WechatLoginRequestDTO dto) {
        log.info("接收到微信登录回调,code:{}", dto.getCode());
        //参数有效性
        if (StringUtils.isBlank(dto.getCode())) {
            return BsResult.error(ResultCode.PARAM_MISS);
        }
        //通过code获取access_token
        String accessTokenUrl = new StringBuilder("https://api.weixin.qq.com/sns/oauth2/access_token?appid=").append(appId)
                .append("&secret=").append(secret)
                .append("&code=").append(dto.getCode())
                .append("&grant_type=authorization_code").toString();
        log.info("微信登录-accessTokenUrl：{}", accessTokenUrl);
        String accessTokenResponse = HttpClientUtil.get(accessTokenUrl, "UTF-8");
        log.info("微信登录-accessTokenResponse：{}", accessTokenResponse);
        if (StringUtils.isBlank(accessTokenResponse)) {
            log.info("微信登录-accessTokenResponse为空");
            return BsResult.error(ResultCode.INTERNAL_SERVER_ERROR);
        }
        JSONObject json = JSONObject.parseObject(accessTokenResponse);
        if (!StringUtil.isEmpty(json.getString("errcode"))) {
            log.info("微信登录-异常");
            return BsResult.error(ResultCode.INTERNAL_SERVER_ERROR);
        }
        boolean registerResult = false;
        try {
            String openId = json.getString("openid");
            User user = userService.queryByOpenId(openId);
            if (user == null) {
                //新账号，返回openid给前端，用户获取手机验证码后，前端再调用/api/user/login接口完成注册&登录
                Map<String, Object> result = new HashMap<>();
                result.put("openId", openId);
                return BsResult.success(result);
            }
            //获得新会话
            ISession session = createSession(user.getId());
            HttpServletRequest request = getRequest();
            HttpServletResponse response = getResponse();
            Cookie cookie = new Cookie(Constant.cookie4SessionName, session.getSessionId());
            cookie.setPath("/");
            cookie.setHttpOnly(true);
            response.addCookie(cookie);
            RequestVO clientInfo = getClientRequest(request);
            UserLoginLog newLoginLog = userLoginLogService.save(user.getId(), session.getSessionId(), LoginTypeEnum.WECAHT.getCode(), new Date(),
                    clientInfo.getClientIp(), clientInfo.getClientOs(), clientInfo.getClientBrowser(), clientInfo.getClientOrigin());
            log.info("用户微信扫码登录成功，newLoginLog={}", newLoginLog.getId());
            registerResult = true;
        } catch (Exception e) {
            log.error("UserController.wechatLogin(String,String) error", e);
        }
        Map<String, Object> result = new HashMap<>();
        result.put("result", registerResult);
        result.put("message", registerResult ? "登录成功" : "登录失败");
        return BsResult.success(result);
    }

    @PostMapping("/login")
    @ApiOperation(value = "用户登录", notes = "用户登录 / 用户通过微信扫码绑定手机号后注册")
    @ResponseBody
    public BsResult login(@RequestBody LoginRequestDTO dto) {
        //检查手机号码的有效性
        if (StringUtils.isBlank(dto.getMobile()) || !PhoneUtil.isMobile(dto.getMobile())) {
            return BsResult.error(ResultCode.PARAM_VALID_ERROR);
        }
        SmsLog smsLog = null;
        if (StringUtils.isNotBlank(dto.getIdentifyCode()) && dto.getIdentifyCode().equals(Constant.universalIdentifyCode)) {
            log.info("使用万能验证码登录dto={}", JSON.toJSONString(dto));
        } else {
            //检查短信验证码的正误
            smsLog = smsLogService.queryByCode(dto.getIdentifyCode());
            if (smsLog == null || !dto.getMobile().equals(smsLog.getMobile())) {
                return BsResult.error(ResultCode.CODE_INVALID);
            }
            //超出5分钟
            if (DateUtil.getMinuteOfTwoDate(smsLog.getCreateTime(), new Date()) > 5) {
                return BsResult.error(ResultCode.CODE_EXPIRED);
            }
        }
        boolean registerResult = false;
        try {
            User user = userService.queryByMobile(dto.getMobile());
            if (user == null) {
                //注册新账号
                user = userService.save(dto.getMobile(), dto.getOpenId(), null);
                userPrivilegeService.updateUserPrivilege(user.getId(), UserPrivilegeEnum.AI_CHECKTEXT.getCode(), 1000);
                log.info("用户注册成功dto={}", JSON.toJSONString(dto));
            }
            //获得新会话
            ISession session = createSession(user.getId());
            HttpServletRequest request = getRequest();
            HttpServletResponse response = getResponse();
            Cookie cookie = new Cookie(Constant.cookie4SessionName, session.getSessionId());
            cookie.setMaxAge(Constant.cookieMaxAge);
            cookie.setPath("/");
            cookie.setHttpOnly(true);
            response.addCookie(cookie);
            RequestVO clientInfo = getClientRequest(request);
            UserLoginLog newLoginLog = userLoginLogService.save(user.getId(), session.getSessionId(), LoginTypeEnum.IDENTIFYCODE.getCode(), new Date(),
                    clientInfo.getClientIp(), clientInfo.getClientOs(), clientInfo.getClientBrowser(), clientInfo.getClientOrigin());
            log.info("用户登录成功dto={}, newLoginLog={}", JSON.toJSONString(dto), newLoginLog.getId());
            if (smsLog != null) {
                smsLogService.checkedById(smsLog.getId(), user.getId());
            }
            registerResult = true;
        } catch (Exception e) {
            log.error("UserController.login(LoginRequestDTO) error", e);
        }
        Map<String, Object> result = new HashMap<>();
        result.put("result", registerResult);
        result.put("message", registerResult ? "登录成功" : "登录失败");
        return BsResult.success(result);
    }

    @PostMapping("/logout")
    @ApiOperation(value = "用户退出", notes = "用户退出")
    @ResponseBody
    public BsResult logout() {
        String sessionId = deleteSession();
        //记录登出时间
        userLoginLogService.logout(sessionId);
        HttpServletResponse response = getResponse();
        Cookie cookie = new Cookie(Constant.cookie4SessionName, "");
        cookie.setPath("/");
        cookie.setHttpOnly(true);
        response.addCookie(cookie);
        Map<String, Object> result = new HashMap<>();
        result.put("result", true);
        result.put("message", "登出成功");
        return BsResult.success(result);
    }

    @PostMapping("/info")
    @ApiOperation(value = "获取用户信息", notes = "获取用户信息")
    @ResponseBody
    public BsResult userinfo() {
        ISession session = getSession();
        TblUser user = userService.getById(session.getUserId());
        if (user == null) {
            return BsResult.error(ResultCode.FAILURE);
        }
        UserVO userVO = new UserVO()
                .setVipUser(user.getVipUser())
                .setUserNick(user.getNick())
                .setVipEndTime(user.getVipEndTime())
                .setVipVersion(VipGoodsEnum.FreeEditioin.getVipVersion())
                .setVipVersionDesc(VipGoodsEnum.FreeEditioin.getVipVersionDesc());
        //付费用户设置套餐信息
        if (user.getVipLevelCode() != null && user.getVipLevelCode() > 0) {
            VipGoods vipGoods = vipGoodsService.queryByVipLevel(user.getVipLevelCode());
            userVO.setVipVersion(vipGoods.getVipVersion())
                    .setVipVersionDesc(vipGoods.getVipVersionDesc());
        }
        return BsResult.success(userVO);
    }

    @GetMapping("/userPrivilege")
    @ApiOperation(value = "获取用户权益次数", notes = "获取用户权益次数")
    @ResponseBody
    public BsResult userPrivilege(@RequestParam(required = true) String code) {
        if (StringUtils.isBlank(code)) {
            return BsResult.error(ResultCode.PARAM_MISS);
        }
        UserPrivilegeEnum userPrivilegeEnum = UserPrivilegeEnum.getByCode(code);
        if (userPrivilegeEnum == null) {
            return BsResult.error(ResultCode.PARAM_VALID_ERROR);
        }
        TblUser user = getUser();
        if (user == null) {
            return BsResult.error(ResultCode.FAILURE);
        }
        UserPrivilege userPrivilege = userPrivilegeService.queryByUserIdAndPrivilegeName(user.getId(), userPrivilegeEnum.getCode());
        Integer times = 0;
        if (null == userPrivilege) {
            //说明这是免费用户
            times = null;
        } else {
            times = userPrivilege.getRemainTimes();
        }
        return BsResult.success(times);
    }

    @GetMapping("/exppackage")
    @ApiOperation(value = "获取用户资源包次数")
    @ResponseBody
    public BsResult userExppackage(@RequestParam(required = true) Integer type) {
        if (type == null) {
            return BsResult.error(ResultCode.PARAM_MISS);
        }
        UserExpPackageTypeEnum userExpPackageTypeEnum = UserExpPackageTypeEnum.getByCode(type);
        if (userExpPackageTypeEnum == null) {
            return BsResult.error(ResultCode.PARAM_VALID_ERROR);
        }
        TblUser user = getUser();
        if (user == null) {
            return BsResult.error(ResultCode.FAILURE);
        }
        TblUserExppackage userExppackage = userExppackageService.queryUserExppackage(user.getId(), userExpPackageTypeEnum);
        Integer times = 0;
        if (userExppackage != null && userExppackage.getExpCount() != null) {
            times = userExppackage.getExpCount();
        }
        return BsResult.success(times);
    }

}
